#include "ExampleApplication.h"
#include "goAnimated.h"

class GameListener : public ExampleFrameListener
{
	private:

	public:
		GameListener(Ogre::RenderWindow *win, Ogre::Camera *cam) :
			ExampleFrameListener(win, cam) { }

		void _disableAllStates()
		{
			Ogre::SceneManager *pSceneMgr = Ogre::Root::getSingleton().getSceneManager("ExampleSMInstance");
			Ogre::Entity *knight = pSceneMgr->getEntity("Knight");

			Ogre::AnimationStateSet *animSet = knight->getAllAnimationStates();
			Ogre::AnimationStateIterator iter = animSet->getAnimationStateIterator();
			while (iter.hasMoreElements())
			{
				Ogre::AnimationState *state = iter.getNext();
				if (state->hasBlendMask())
					state->destroyBlendMask();
				state->setEnabled(0);
				state->setTimePosition(0);
				state->setLoop(1);
			}

		}

		void getInfectedBoneHandles(Ogre::Bone* in_bone, std::vector<unsigned short> &handles)
		{
			handles.push_back(in_bone->getHandle());

			Ogre::Node::ChildNodeIterator iter = in_bone->getChildIterator();
			while(iter.hasMoreElements())
			{
				getInfectedBoneHandles(dynamic_cast<Ogre::Bone*>(iter.getNext()), handles);
			}
		}

		bool frameRenderingQueued(const Ogre::FrameEvent& evt)
		{

			if (ExampleFrameListener::frameRenderingQueued(evt) == 0)
				return (0);

			Ogre::SceneManager *pSceneMgr = Ogre::Root::getSingleton().getSceneManager("ExampleSMInstance");
			Ogre::Entity *knight = pSceneMgr->getEntity("Knight");

			

			// see if the animation needs to be changed
			if(mKeyboard->isKeyDown(OIS::KC_A)) {
				_disableAllStates();	
				knight->getAnimationState("Ready")->setEnabled(1);
			OverlayManager::getSingleton().getOverlayElement("Animation/Current")->setCaption("Current Animation: Ready");
			}
			if(mKeyboard->isKeyDown(OIS::KC_S)) {
				_disableAllStates();	
				knight->getAnimationState("Run")->setEnabled(1);
			OverlayManager::getSingleton().getOverlayElement("Animation/Current")->setCaption("Current Animation: Run");
			}
			if(mKeyboard->isKeyDown(OIS::KC_D)) {
				_disableAllStates();	
				knight->getAnimationState("Attack1")->setEnabled(1);
			OverlayManager::getSingleton().getOverlayElement("Animation/Current")->setCaption("Current Animation: Attack1");
			}
			if(mKeyboard->isKeyDown(OIS::KC_Z)) {
				_disableAllStates();	
				Ogre::AnimationState *attack = knight->getAnimationState("Attack1");
				Ogre::AnimationState *run = knight->getAnimationState("Run");
				attack->createBlendMask(knight->getSkeleton()->getNumBones(), 0);
				run->createBlendMask(knight->getSkeleton()->getNumBones(), 1);
				std::vector<unsigned short> h;
				getInfectedBoneHandles(knight->getSkeleton()->getBone("Bip01_Spine1"), h);
				for(int i=0; i<h.size(); i++)
				{
					run->setBlendMaskEntry(h[i], 0);
					attack->setBlendMaskEntry(h[i], 1);
				}
				run->setEnabled(1);
				attack->setEnabled(1);
			OverlayManager::getSingleton().getOverlayElement("Animation/Current")->setCaption("Current Animation: Run and Attack");
			}
			if(mKeyboard->isKeyDown(OIS::KC_X)) {
				_disableAllStates();	
				Ogre::AnimationState *run = knight->getAnimationState("Run");
				run->createBlendMask(knight->getSkeleton()->getNumBones(), 1);
				unsigned short h = knight->getSkeleton()->getBone("Bip01_R_Calf")->getHandle();
				run->setBlendMaskEntry(h, .1);
				run->setEnabled(1);
			OverlayManager::getSingleton().getOverlayElement("Animation/Current")->setCaption("Current Animation: Run With Limp");
			}
			if(mKeyboard->isKeyDown(OIS::KC_C)) {
				_disableAllStates();	
				Ogre::AnimationState *run = knight->getAnimationState("Run");
				run->createBlendMask(knight->getSkeleton()->getNumBones(), 1);
				unsigned short h = knight->getSkeleton()->getBone("Bip01_R_Forearm")->getHandle();
				run->setBlendMaskEntry(h, .1);
				run->setEnabled(1);
			OverlayManager::getSingleton().getOverlayElement("Animation/Current")->setCaption("Current Animation: Run With Disabled Arm");
			}


			Ogre::AnimationStateSet *animSet = knight->getAllAnimationStates();
			Ogre::AnimationStateIterator iter = animSet->getAnimationStateIterator();
			while (iter.hasMoreElements())
			{
				Ogre::AnimationState *state = iter.getNext();
				if (state->getEnabled())
					state->addTime(evt.timeSinceLastFrame);
			}

			// update the current animation caption


			return (1);
		}
};
		

class Game : public ExampleApplication
{

	virtual void createFrameListener()
	{
		mFrameListener = new GameListener(mWindow, mCamera);
		mRoot->addFrameListener(mFrameListener);
	}

	void getInfectedBoneHandles(Ogre::Bone* in_bone, std::vector<unsigned short> &handles)
	{
		handles.push_back(in_bone->getHandle());

		Ogre::Node::ChildNodeIterator iter = in_bone->getChildIterator();
		while(iter.hasMoreElements())
		{
			getInfectedBoneHandles(dynamic_cast<Ogre::Bone*>(iter.getNext()), handles);
		}
	}

	void createScene()
	{
		Ogre::AnimationState *state;

		mSceneMgr->setAmbientLight(ColourValue(0.8, 0.8, 0.8));

		// create the sword
		Ogre::Entity *sword = mSceneMgr->createEntity("Sword", "sword.mesh");
		Ogre::Quaternion quatRotate = Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_X);

		// create the knight
		goAnimated go;
		go.load("knight.mesh", mSceneMgr);

		go.createAllStatesFromXML("knight.xml");
		go.addAnimationsFromXML("knight.xml");

		//go._outputBoneList(std::cerr);
		//go._outputAnimationList(std::cerr);

		Ogre::Entity *knight = mSceneMgr->getEntity("Knight");
		knight->getSkeleton()->setBlendMode(Ogre::ANIMBLEND_CUMULATIVE);
		knight->attachObjectToBone("Bip01_R_Finger1", sword, quatRotate, Ogre::Vector3::ZERO);


		state = knight->getAnimationState("Ready");
		state->setEnabled(1);
		state->setTimePosition(0);
		state->setLoop(1);

		go.setAnimation("RunAttack1", 1);


		// show the overlay
		OverlayManager::getSingleton().getOverlayElement("Animation/Current")->setCaption("Current Animation: Ready");
		OverlayManager::getSingleton().getByName("Animation/Overlay")->show();

		mCamera->setPosition(-4.1, 49, 420);
	}

};
